package com.osard.editspinner;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.text.Editable;
import android.text.InputFilter;
import android.text.InputType;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.method.DigitsKeyListener;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListPopupWindow;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;

import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes;
import androidx.annotation.StringRes;
import androidx.appcompat.widget.AppCompatEditText;
import androidx.appcompat.widget.AppCompatImageView;

import java.util.List;


public class AppCompatEditSpinner extends RelativeLayout implements View.OnClickListener, AdapterView.OnItemClickListener, TextWatcher {

    private AppCompatEditText editText;
    private AppCompatImageView mRightIv;
    private View mRightImageTopView;

    private ListPopupWindow popupWindow;

    private BaseEditSpinnerAdapter adapter;

    private boolean rightImageDropShowAllItem;

    private boolean selectItemClick;
    private boolean isPopupWindowShowing;
    private Animation mAnimation;
    private Animation mResetAnimation;

    private int maxLength;
    private int inputType;
    private String digits;

    //下拉选的背景
    private Drawable spinnerBackground;
    //匹配文本的颜色
    private String matchTextColor;
    //匹配文本时是否忽略字母大小写
    private boolean matchIgnoreCase;
    //待选项的文本颜色
    private ColorStateList spinnerItemTextColor;
    //待选项的文本大小，单位：SP
    private float spinnerItemTextSize;

    public AppCompatEditSpinner(Context context, AttributeSet attrs) {
        super(context, attrs);

        initView(attrs);
        initAnimation();
    }

    /**
     * 使用SimpleAdapter加载数据
     * <p>
     * 需要在
     * {@link AppCompatEditSpinner#setMatchIgnoreCase(boolean)}、
     * {@link AppCompatEditSpinner#setMatchTextColor(String)}、
     * {@link AppCompatEditSpinner#setSpinnerItemTextColor(int)}、
     * {@link AppCompatEditSpinner#setSpinnerItemTextSize(int)}、
     * {@link AppCompatEditSpinner#setSpinnerBackground(int)}
     * 属性设置之后调用。
     */
    public void setItemData(List<String> data) {
        adapter = new SimpleAdapter(getContext(), data);
        setAdapter(adapter);
    }

    /**
     * 设置文本
     */
    public void setText(@StringRes int text) {
        setText(getContext().getString(text));
    }

    /**
     * 设置文本
     */
    public void setText(String text) {
        editText.setText(text);
    }

    /**
     * 设置Hint文本
     */
    public void setHint(@StringRes int hint) {
        setHint(getContext().getString(hint));
    }

    /**
     * 设置Hint文本
     */
    public void setHint(String hint) {
        editText.setHint(hint);
    }

    /**
     * 设置Hint的文本颜色
     */
    public void setHintTextColor(@ColorInt int color) {
        editText.setHintTextColor(color);
    }

    /**
     * 设置背景
     */
    public void setEditBackgroundResource(@DrawableRes int resource) {
        editText.setBackgroundResource(resource);
    }

    /**
     * 设置输入文字字体大小，单位：sp
     */
    public void setEditTextSize(int size) {
        editText.setTextSize(TypedValue.COMPLEX_UNIT_SP, size);
    }

    /**
     * 设置输入文字颜色
     */
    public void setEditTextColor(@ColorInt int color) {
        editText.setTextColor(color);
    }

    /**
     * 设置输入限制最大行数
     */
    public void setEditMaxLines(int maxLines) {
        editText.setMaxLines(maxLines);
    }

    /**
     * 设置输入限制最大字符长度
     */
    public void setEditMaxLength(int maxLength) {
        this.maxLength = maxLength;
        setEditLimit();
    }

    /**
     * 设置输入限制类型
     * <p>
     * 例如：{@link  InputType#TYPE_CLASS_TEXT}
     */
    public void setEditInputType(int inputType) {
        this.inputType = inputType;
        setEditLimit();
    }

    /**
     * 设置输入限制字符
     */
    public void setEditDigits(@StringRes int digits) {
        setEditDigits(getContext().getString(digits));
    }

    /**
     * 设置输入限制字符
     */
    public void setEditDigits(String digits) {
        this.digits = digits;
        setEditLimit();
    }

    /**
     * 设置是否隐藏右侧下拉选图标
     */
    public void setRightImageGone(boolean rightImageGone) {
        mRightIv.setVisibility(rightImageGone ? GONE : VISIBLE);
    }

    /**
     * 右侧图片展开下拉选时是否显示全部数据，默认：点击时显示和当前输入匹配的数据
     */
    public void setRightImageDropShowAllItem(boolean rightImageDropShowAllItem) {
        this.rightImageDropShowAllItem = rightImageDropShowAllItem;
    }

    /**
     * 匹配字符的颜色，忽略字母大小写时，此属性无效
     *
     * <p>
     * 必须在{@link AppCompatEditSpinner#setItemData(List)}
     * 或者{@link AppCompatEditSpinner#setAdapter(BaseEditSpinnerAdapter)} 调用之前进行设置
     * <p>
     * {@link AppCompatEditSpinner#setItemData(List)}
     * 或者{@link AppCompatEditSpinner#setAdapter(BaseEditSpinnerAdapter)} 调用后不可再次修改
     *
     * @param matchTextColor RGB形式，需要包含#号，例如：“#000000”
     */
    public void setMatchTextColor(String matchTextColor) {
        this.matchTextColor = matchTextColor;
    }

    /**
     * 匹配字符时是否忽略字母大小写，默认不忽略。
     *
     * <p>
     * 必须在{@link AppCompatEditSpinner#setItemData(List)}
     * 或者{@link AppCompatEditSpinner#setAdapter(BaseEditSpinnerAdapter)}调用之前进行设置
     * <p>
     * {@link AppCompatEditSpinner#setItemData(List)}
     * 或者{@link AppCompatEditSpinner#setAdapter(BaseEditSpinnerAdapter)} 调用后不可再次修改
     */
    public void setMatchIgnoreCase(boolean matchIgnoreCase) {
        this.matchIgnoreCase = matchIgnoreCase;
    }

    /**
     * 待选项的颜色，默认黑色
     *
     * <p>
     * 必须在{@link AppCompatEditSpinner#setItemData(List)}
     * 或者{@link AppCompatEditSpinner#setAdapter(BaseEditSpinnerAdapter)}调用之前进行设置
     * <p>
     * {@link AppCompatEditSpinner#setItemData(List)}
     * 或者{@link AppCompatEditSpinner#setAdapter(BaseEditSpinnerAdapter)} 调用后不可再次修改
     */
    public void setSpinnerItemTextColor(@ColorInt int spinnerItemTextColor) {
        this.spinnerItemTextColor = ColorStateList.valueOf(spinnerItemTextColor);
    }

    /**
     * 待选项的字体大小，单位sp。
     *
     * <p>
     * 必须在{@link AppCompatEditSpinner#setItemData(List)}
     * 或者{@link AppCompatEditSpinner#setAdapter(BaseEditSpinnerAdapter)}调用之前进行设置
     * <p>
     * {@link AppCompatEditSpinner#setItemData(List)}
     * 或者{@link AppCompatEditSpinner#setAdapter(BaseEditSpinnerAdapter)} 调用后不可再次修改
     */
    public void setSpinnerItemTextSize(int spinnerItemTextSize) {
        this.spinnerItemTextSize = spinnerItemTextSize;
    }

    /**
     * 待选项的背景
     *
     * <p>
     * 必须在{@link AppCompatEditSpinner#setItemData(List)}
     * 或者{@link AppCompatEditSpinner#setAdapter(BaseEditSpinnerAdapter)}调用之前进行设置
     * <p>
     * {@link AppCompatEditSpinner#setItemData(List)}
     * 或者{@link AppCompatEditSpinner#setAdapter(BaseEditSpinnerAdapter)} 调用后不可再次修改
     */
    public void setSpinnerBackground(Drawable spinnerBackground) {
        this.spinnerBackground = spinnerBackground;
    }

    /**
     * 待选项的背景
     *
     * <p>
     * 必须在{@link AppCompatEditSpinner#setItemData(List)}
     * 或者{@link AppCompatEditSpinner#setAdapter(BaseEditSpinnerAdapter)}调用之前进行设置
     * <p>
     * {@link AppCompatEditSpinner#setItemData(List)}
     * 或者{@link AppCompatEditSpinner#setAdapter(BaseEditSpinnerAdapter)} 调用后不可再次修改
     */
    @SuppressLint("UseCompatLoadingForDrawables")
    public void setSpinnerBackground(@DrawableRes int spinnerBackground) {
        this.spinnerBackground = getResources().getDrawable(spinnerBackground);
    }

    /**
     * 获取输入的文本
     */
    public String getText() {
        Editable editable = editText.getText();
        return null == editable ? "" : editable.toString();
    }

    /**
     * 设置下拉选图标
     */
    public void setRightImageDrawable(Drawable drawable) {
        mRightIv.setImageDrawable(drawable);
    }

    /**
     * 设置下拉选图标
     */
    public void setRightImageResource(@DrawableRes int res) {
        mRightIv.setImageResource(res);
    }

    /**
     * 获取输入控件EditText，可做特殊配置
     */
    public AppCompatEditText getEditText() {
        return editText;
    }

    /**
     * 获取右侧ImageView，可做特殊配置
     */
    public AppCompatImageView getRightImageView() {
        return mRightIv;
    }

    /**
     * 使用继承{@link BaseEditSpinnerAdapter}的适配器加载数据
     * <p>
     * 需要在
     * {@link AppCompatEditSpinner#setMatchIgnoreCase(boolean)}、
     * {@link AppCompatEditSpinner#setMatchTextColor(String)}、
     * {@link AppCompatEditSpinner#setSpinnerItemTextColor(int)}、
     * {@link AppCompatEditSpinner#setSpinnerItemTextSize(int)}、
     * {@link AppCompatEditSpinner#setSpinnerBackground(int)}
     * 属性设置之后调用
     */
    public void setAdapter(BaseEditSpinnerAdapter adapter) {
        this.adapter = adapter;
        this.adapter.setMatchTextColor(matchTextColor);
        this.adapter.setMatchIgnoreCase(matchIgnoreCase);
        this.adapter.setSpinnerItemTextColor(spinnerItemTextColor);
        this.adapter.setSpinnerItemTextSize(spinnerItemTextSize);
        setBaseAdapter(this.adapter);
    }

    private void initAnimation() {
        mAnimation = new RotateAnimation(0, -90, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        mAnimation.setDuration(300);
        mAnimation.setFillAfter(true);

        mResetAnimation = new RotateAnimation(-90, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        mResetAnimation.setDuration(300);
        mResetAnimation.setFillAfter(true);
    }

    private void initView(AttributeSet attrs) {
        LayoutInflater.from(getContext()).inflate(R.layout.app_compat_edit_spinner, this);
        editText = findViewById(R.id.spinner_edit_text);
        mRightIv = findViewById(R.id.spinner_expand);
        mRightImageTopView = findViewById(R.id.spinner_expand_above);
        mRightImageTopView.setOnClickListener(this);
        mRightImageTopView.setClickable(false);
        mRightIv.setOnClickListener(this);
        mRightIv.setRotation(90);
        editText.addTextChangedListener(this);

        TypedArray tArray = getContext().obtainStyledAttributes(attrs,
                R.styleable.AppCompatEditSpinner);

        editText.setText(tArray.getString(R.styleable.AppCompatEditSpinner_text));

        editText.setHint(tArray.getString(R.styleable.AppCompatEditSpinner_hint));
        ColorStateList hintTextColor = tArray.getColorStateList(R.styleable.AppCompatEditSpinner_hintTextColor);
        if (null != hintTextColor) {
            editText.setHintTextColor(hintTextColor);
        }

        int bg = tArray.getResourceId(R.styleable.AppCompatEditSpinner_editBackground, 0);
        if (bg != 0) {
            editText.setBackgroundResource(bg);
        }

        float editTextSize = tArray.getDimension(R.styleable.AppCompatEditSpinner_editTextSize, 0);
        if (editTextSize != 0) {
            editText.setTextSize(TypedValue.COMPLEX_UNIT_PX, editTextSize);
        }

        ColorStateList editTextColor = tArray.getColorStateList(R.styleable.AppCompatEditSpinner_editTextColor);
        if (null != editTextColor) {
            editText.setTextColor(editTextColor);
        }

        int maxLines = tArray.getInt(R.styleable.AppCompatEditSpinner_editMaxLines, 0);
        if (maxLines > 0) {
            editText.setMaxLines(maxLines);
        }

        //edit 长度、输入类型、输入字符限制
        maxLength = tArray.getInt(R.styleable.AppCompatEditSpinner_editMaxLength, 0);
        inputType = tArray.getInt(R.styleable.AppCompatEditSpinner_editInputType, -1);
        digits = tArray.getString(R.styleable.AppCompatEditSpinner_editDigits);
        setEditLimit();

        int imageId = tArray.getResourceId(R.styleable.AppCompatEditSpinner_rightImage, 0);
        if (imageId != 0) {
            mRightIv.setImageResource(imageId);
        }

        boolean rightImageGone = tArray.getBoolean(R.styleable.AppCompatEditSpinner_rightImageGone, false);
        mRightIv.setVisibility(rightImageGone ? GONE : VISIBLE);
        //读取点击右侧图片时是否显示全部数据
        rightImageDropShowAllItem = tArray.getBoolean(R.styleable.AppCompatEditSpinner_rightImageDropShowAllItem, false);

        //读取匹配字符部分显示的颜色，由ARGB转为RGB表示
        CharSequence sequence = tArray.getText(R.styleable.AppCompatEditSpinner_spinnerItemMatchTextColor);
        if (!TextUtils.isEmpty(sequence)) {
            matchTextColor = String.format("#%s", sequence.toString().substring(3));
        }
        //读取匹配时是否忽略字母大小写
        matchIgnoreCase = tArray.getBoolean(R.styleable.AppCompatEditSpinner_spinnerItemMatchIgnoreCase, false);
        //读取待选项的文本颜色
        spinnerItemTextColor = tArray.getColorStateList(R.styleable.AppCompatEditSpinner_spinnerItemTextColor);
        //读取待选项的文本大小
        float itemTextSize = tArray.getDimensionPixelSize(R.styleable.AppCompatEditSpinner_spinnerItemTextSize, 0);
        if (itemTextSize != 0) {
            spinnerItemTextSize = pxToDp(itemTextSize);
        }
        //待选项的背景
        spinnerBackground = tArray.getDrawable(R.styleable.AppCompatEditSpinner_spinnerBackground);

        tArray.recycle();
    }

    private void setEditLimit() {
        if (maxLength > 0) {
            editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength)});
        }
        if (inputType > -1) {
            editText.setInputType(inputType);
        }
        if (!TextUtils.isEmpty(digits)) {
            editText.setKeyListener(DigitsKeyListener.getInstance(digits));
        }
    }

    private void setBaseAdapter(BaseAdapter adapter) {
        if (popupWindow == null) {
            initPopupWindow();
        }
        popupWindow.setAdapter(adapter);
    }

    private void initPopupWindow() {
        popupWindow = new ListPopupWindow(getContext()) {
            @Override
            public boolean isShowing() {
                return isPopupWindowShowing;
            }

            @Override
            public void show() {
                super.show();
                isPopupWindowShowing = true;
                mRightImageTopView.setClickable(true);
                mRightIv.startAnimation(mAnimation);
            }
        };
        if (null != spinnerBackground) {
            popupWindow.setBackgroundDrawable(spinnerBackground);
        }
        popupWindow.setOnItemClickListener(this);
        popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED);
        popupWindow.setPromptPosition(ListPopupWindow.POSITION_PROMPT_BELOW);
        popupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
        popupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
        popupWindow.setAnchorView(editText);
        popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
            @Override
            public void onDismiss() {
                isPopupWindowShowing = false;
                mRightIv.startAnimation(mResetAnimation);
            }
        });
    }


    @Override
    public final void onClick(View v) {
        if (adapter == null || popupWindow == null) {
            return;
        }
        if (v.equals(mRightImageTopView)) {
            v.setClickable(false);
            return;
        }
        if (popupWindow.isShowing()) {
            popupWindow.dismiss();
        } else {
            showFilterData(rightImageDropShowAllItem ? null : getText());
        }
    }

    @Override
    public final void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        selectItemClick = true;

        editText.setText(adapter.getItemString(position));
        this.requestFocus();
        editText.requestFocus();
        editText.setSelection(getText().length());
        mRightImageTopView.setClickable(false);
        popupWindow.dismiss();

        selectItemClick = false;
    }

    @Override
    public final void beforeTextChanged(CharSequence s, int start, int count, int after) {

    }

    @Override
    public final void onTextChanged(CharSequence s, int start, int before, int count) {

    }

    @Override
    public final void afterTextChanged(Editable s) {
        //选中待选项填入edit时，不触发此事件
        if (selectItemClick) return;

        String key = s.toString();
        editText.setSelection(key.length());
        if (!TextUtils.isEmpty(key)) {
            showFilterData(key);
        } else {
            if (popupWindow != null) {
                popupWindow.dismiss();
            }
        }
    }

    private void showFilterData(String key) {
        if (popupWindow == null || adapter == null) {
            if (popupWindow != null) {
                popupWindow.dismiss();
            }
            return;
        }
        if (adapter.onFilter(key)) {
            popupWindow.dismiss();
        } else {
            popupWindow.show();
        }

    }

    private int pxToDp(float px) {
        float scale = getResources().getDisplayMetrics().density;
        return (int) (px / scale + 0.5f);
    }
}
